package com.ruoyi.business.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.ruoyi.bizsys.domain.*;
import com.ruoyi.bizsys.mapper.*;
import com.ruoyi.bizsys.service.*;
import com.ruoyi.bizsys.utils.BizConstants;
import com.ruoyi.business.component.RepaymentMqSendService;
import com.ruoyi.business.processIou.service.ProcessForIouDefferredService;
import com.ruoyi.business.service.asyncservice.AsyncRepaymentService;
import com.ruoyi.business.service.impl.BaseService;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.RspEnmu;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.Func;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author wqg
 * @description QuidckRepay
 * @date 2022/4/18
 */
@Slf4j
@Component
public class QuickRepayService extends BaseService {
    @Autowired
    ICustTransactionSettingService custTransactionSettingService;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Autowired
    RedisCache redisCache;
    @Autowired
    ICustBankCardService custBankCardService;
    @Autowired
    IBLoanInfoService bLoanInfoService;
    @Autowired
    RepaymentMqSendService repaymentMqService;
    @Autowired
    DoCalCustReduce doCalCustReduce;
    @Autowired
    IRepaymentService repaymentService;

    @Autowired
    ICreditAccountService creditAccountService;
    @Resource
    LoanIouMapper loanIouMapper;
    @Autowired
    ProductDeferredInfoMapper productDeferredInfoMapper;

    @Autowired
    ProductInfoMapper productInfoMapper;
    @Autowired
    LoanDeferredOrderMapper loanDeferredOrderMapper;

    @Autowired
    ILoanDeferredOrderService loanDeferredOrderService;

    @Autowired
    ProcessForIouDefferredService processForIouDefferredService;

    @Autowired
    ILoanIouService loanIouService;

    @Autowired
    IDoRepaymentLastService doRepaymentLastService;

    @Autowired
    ISysConfigService sysConfigService;

    @Autowired
    RepaymentOrderMapper repaymentOrderMapper;

    @Autowired
    AsyncRepaymentService asyncRepayMentService;

    //获取主动还款
    public JSONObject loanRepay(JSONObject dataJson) {
        log.info("主动还款参数:{}", dataJson.toJSONString());
        JSONObject rsp = new JSONObject();
        String userUUId = dataJson.get("userId").toString();
        String serialNo = dataJson.get("loanNo").toString();
        String cardId = dataJson.get("cardId").toString();
        String password = dataJson.get("password").toString();
        // 是否使用了钱包
        boolean useWallet = dataJson.getBoolean("useWallet");
        // 是否只用钱包
        boolean isJustWallet = dataJson.getBoolean("isJustWallet");
        boolean passwordCheck = isPasswordCheck(userUUId, password);
        if (!passwordCheck) {
            rsp.put("result", "-1");
            return rsp;
        }
        if(isJustWallet){
            return doRepayJustByWallet(rsp, serialNo);
        }
        if (useWallet) {
            //使用钱包，调用钱包获取金额（冻结钱）
            doRepayWallet(rsp, serialNo, cardId);
        } else {
            doRepay(rsp, serialNo, cardId);
        }
        return rsp;
    }

    /**
     * 主动还款-延期还款-选择卡
     *
     * @param dataJson
     * @return
     */
    public JSONObject loanRepayDeferred(JSONObject dataJson) {
        log.info("主动还款-延期还款，参数:{}", dataJson.toJSONString());
        JSONObject rsp = new JSONObject();
        String userUUId = dataJson.get("userId").toString();
        String serialNo = dataJson.get("loanNo").toString();
        String cardId = dataJson.get("cardId").toString();
        String password = dataJson.get("password").toString();
        int deferredId = dataJson.getIntValue("deferredId");
        // 是否使用了钱包
        boolean useWallet = dataJson.getBoolean("useWallet");
        // 是否只用钱包
        boolean isJustWallet = dataJson.getBoolean("isJustWallet");
        boolean passwordCheck = isPasswordCheck(userUUId, password);
        if (!passwordCheck) {
            rsp.put("result", "-1");
            return rsp;
        }
        if(isJustWallet){
            return doDeferredRepayJustByWallet(rsp, serialNo,deferredId);
        }
        if (useWallet) {
            //使用钱包，调用钱包获取金额（冻结钱）
            doRepayDeferredWallet(rsp, serialNo, cardId, deferredId);
        } else {
            doRepayDeferred(rsp, serialNo, cardId, deferredId);
        }
        return rsp;
    }

    /**
     * 只用钱包还款
     * @param rsp
     * @param serialNo
     */
    private JSONObject doRepayJustByWallet(JSONObject rsp, String serialNo) {
        log.info("主动还款-只用钱包还款:serialNo:{}", serialNo);
        LoanIou loanIou = loanIouMapper.getLoanIouByLoanSerialNo(serialNo);
        BigDecimal minPay = LoanIou.calculationOverdueAmount(loanIou);
        JSONObject amtWalletObj = doRepaymentLastService.getAmtWallet(minPay, loanIou.getCustNo(), loanIou.getLoanSerialNo(), false);
        BigDecimal amtWallet = amtWalletObj.getBigDecimal("amtWallet");
        String walletNo = amtWalletObj.getString("walletOrderNo");
        if (amtWallet.compareTo(minPay) < 0) {
            log.info("主动还款-只用钱包还款：钱包余额小于等于于需要支付的，扣掉返回钱包余额,{},{}", amtWallet, minPay);
            log.info("主动还款-只用钱包还款：全额还款失败，解冻钱包");
            doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
            throw new BusinessException(RspEnmu.REPAYMENT_WALLET_NOT_ENOUGH);
        }
        log.info("主动还款-只用钱包还款：钱包余额够支付全部费用,{},{}", amtWallet, minPay);
        doRepayAllWithWalletAll(rsp, loanIou, amtWallet, walletNo);
        return rsp;
    }

    /**
     * repayAll 使用钱包还款
     *
     * @param rsp
     * @param serialNo
     * @param cardId
     */
    private void doRepayWallet(JSONObject rsp, String serialNo, String cardId) {
        log.info("主动还款-选择了钱包参数:serialNo:{},cardId:{}", serialNo, cardId);
        LoanIou loanIou = loanIouMapper.getLoanIouByLoanSerialNo(serialNo);
        BigDecimal minPay = LoanIou.calculationOverdueAmount(loanIou);

        JSONObject amtWalletObj = doRepaymentLastService.getAmtWallet(minPay, loanIou.getCustNo(), loanIou.getLoanSerialNo(), false);
        BigDecimal amtWallet = amtWalletObj.getBigDecimal("amtWallet");
        String walletNo = amtWalletObj.getString("walletOrderNo");
        if (amtWallet.compareTo(BigDecimal.ZERO) <= 0) {
            log.info("钱包余额小于等于0,改为卡全款扣款-------");
            doRepay(rsp, serialNo, cardId);
            return;
        }
        // 钱包支付全额还款，不需要等待卡支付回调进行冲账，06-15有沟通
        if (amtWallet.compareTo(minPay) == 0) {
            log.info("钱包余额够支付全部费用,{},{}", amtWallet, minPay);
            doRepayAllWithWalletAll(rsp, loanIou, amtWallet, walletNo);
        } else {
            log.info("钱包余额小于等于于需要支付的，扣掉返回钱包余额,{},{}", amtWallet, minPay);
            doRepayAllWithWalletNotAll(rsp, loanIou, cardId, amtWallet, walletNo, minPay);
        }
    }

    /**
     * @param loanIou
     * @param amtWallet
     * @param walletNo
     */
    private void doRepayAllWithWalletAll(JSONObject rsp, LoanIou loanIou, BigDecimal amtWallet, String walletNo) {
        log.info("使用钱包，全额还款,{},{},{}", loanIou.toString(), amtWallet, walletNo);
        try {
            // 创建repayMentOrder
            RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderRepayAllWalletNoSuccess(
                    loanIou,
                    BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET,
                    "Active", amtWallet, walletNo);
            if (null != repaymentOrder) {
                SendResult sendResult = repaymentMqService.selfWalletForAllPayRepaymentMq(loanIou, repaymentOrder);
                if (!(SendStatus.SEND_OK).equals(sendResult.getSendStatus())) {
                    log.info("钱包全额支付还款，发送mq失败：{}", sendResult);
                    doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                    rsp.put("result", "0");
                    return;
                }
                rsp.put("result", "1");
            } else {
                log.info("使用钱包，全额还款失败；repaymentOrder创建失败");
                doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                rsp.put("result", "0");
                return;
            }
        } catch (Exception e) {
            log.error("钱包全额支付还款err",e);
            doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
            repaymentOrderMapper.updateRepayStatusToFaildByPayTransSerialNo(walletNo);
            throw new BusinessException(RspEnmu.NETWORK_BUSY);
        }
    }

    /**
     * 只用钱包延期还款
     * @param rsp
     * @param serialNo
     */
    private JSONObject doDeferredRepayJustByWallet(JSONObject rsp, String serialNo,int deferredId) {
        log.info("购买延期-只用钱包还款：钱包余额小于等于于需要支付的，扣掉返回钱包余额,serialNo：{},deferredId：{}", serialNo, deferredId);
        LoanIou loanIou = loanIouMapper.getLoanIouByLoanSerialNo(serialNo);
        ProductDeferredInfo productDeferredInfo = productDeferredInfoMapper.selectById(deferredId);
        BigDecimal minPay = processForIouDefferredService.getMinPay(loanIou, productDeferredInfo);
        // 得到选择的延期产品需要支付的金额，远程获取钱包，钱包不够，就返回钱包最小的金额
        JSONObject amtWalletObj = doRepaymentLastService.getAmtWallet(minPay, loanIou.getCustNo(), loanIou.getLoanSerialNo(), true);
        BigDecimal amtWallet = amtWalletObj.getBigDecimal("amtWallet");
        String walletNo = amtWalletObj.getString("walletOrderNo");
        if (amtWallet.compareTo(minPay) < 0) {
            log.info("购买延期-只用钱包还款：钱包余额小于等于于需要支付的，扣掉返回钱包余额,{},{}", amtWallet, minPay);
            log.info("购买延期-只用钱包还款：全额还款失败，解冻钱包");
            doRepaymentLastService.updateWalletOrderToFailed(walletNo, true);
            throw new BusinessException(RspEnmu.REPAYMENT_WALLET_NOT_ENOUGH);
        }
        // 钱包余额
        log.info("购买延期-只用钱包还款：钱包余额够支付的延期费用,{},{}", amtWallet, minPay);
        doRepayDeferredForWclletPayOk(rsp, loanIou, productDeferredInfo, amtWallet, walletNo);
        return rsp;
    }

    private void doRepayDeferredWallet(JSONObject rsp, String serialNo, String cardId, int deferredId) {
        //获取使用的金额，判断是否直接可以抵扣全部
        //不够扣款，生成repayMentOrder 类型设置钱包类型，状态 5 金额 ，loan_offset 生成一个金额相关的，状态2
        // paystask 还款成功，查询生成repayMentOrder,查找是否有

        LoanIou loanIou = loanIouMapper.getLoanIouByLoanSerialNo(serialNo);
        ProductDeferredInfo productDeferredInfo = productDeferredInfoMapper.selectById(deferredId);

        BigDecimal minPay = processForIouDefferredService.getMinPay(loanIou, productDeferredInfo);
        // 得到选择的延期产品需要支付的金额，远程获取钱包，钱包不够，就返回钱包最小的金额
        JSONObject amtWalletObj = doRepaymentLastService.getAmtWallet(minPay, loanIou.getCustNo(), loanIou.getLoanSerialNo(), true);
        BigDecimal amtWallet = amtWalletObj.getBigDecimal("amtWallet");
        String walletNo = amtWalletObj.getString("walletOrderNo");
        if (amtWallet.compareTo(BigDecimal.ZERO) <= 0) {
            log.info("钱包余额小于等于0,改为卡扣延期全款-------");
            doRepayDeferred(rsp, serialNo, cardId, deferredId);
            return;
        }
        if (amtWallet.compareTo(minPay) == 0) {
            // 钱包余额
            log.info("钱包余额够支付的延期费用,{},{}", amtWallet, minPay);
            doRepayDeferredForWclletPayOk(rsp, loanIou, productDeferredInfo, amtWallet, walletNo);
        } else {
            log.info("钱包余额小于等于于需要支付的延期费用，扣掉返回钱包余额,{},{}", amtWallet, minPay);
            // 不够支付，生成部分还款
            doRepayDeferredForWalletNotEnough(rsp, loanIou, productDeferredInfo, cardId, amtWallet, walletNo, minPay);
        }
    }

    private void doRepayDeferredForWalletNotEnough(JSONObject rsp, LoanIou loanIou, ProductDeferredInfo productDeferredInfo
            , String cardId, BigDecimal amtWallet, String walletNo, BigDecimal minPay) {
        log.info("主动还款延期+钱包还款，钱包大于0小于延期购买金额：参数:serialNo:{},cardId:{}", loanIou.getLoanSerialNo(), cardId);
        CustBankCard bankCard = getCustBankCard(cardId);
        setCardCanNotUse(loanIou.getLoanSerialNo(), bankCard, 3);
        //创建 loan_deferred_order 状态状态9申请中 walletNo需要存入订单中，后续需要查出，进行先冲账
        LoanDeferredOrder loanDeferredOrder = createLoanDeferredOrder(loanIou.getLoanSerialNo(), productDeferredInfo.getId(), cardId, walletNo, BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER);
        if (null != loanDeferredOrder) {
            // 创建订单 createRepaymentOrder 钱包的 状态为5
            boolean isOk = createRepaymentOrderDeferWallet(loanDeferredOrder, amtWallet, walletNo, loanIou);
            if (!isOk) {
                updateLoanDeferredOrderFailed(walletNo, loanDeferredOrder);
                rsp.put("result", "0");
            } else {
                // 创建paystask的
                // 卡支付的钱
                try {
                    BigDecimal paystaskAmt = minPay.subtract(amtWallet);
                    boolean result = repaymentService.createRepaymentOrderAndPayTransForDeferNoSuccess(walletNo, paystaskAmt, loanIou, bankCard, loanDeferredOrder, productDeferredInfo);
                    rsp.put("result", result ? "1" : "0");
                } catch (Exception e) {
                    log.error("主动还款延期+钱包还款err",e);
                    rsp.put("result", "0");
                    updateLoanDeferredOrderFailed(walletNo, loanDeferredOrder);
                    throw new BusinessException(RspEnmu.NETWORK_BUSY);
                }
            }
        } else {
            rsp.put("result", "0");
            doRepaymentLastService.updateWalletOrderToFailed(walletNo, true);
        }
    }

    private void updateLoanDeferredOrderFailed(String walletNo, LoanDeferredOrder loanDeferredOrder) {
        if(null!=loanDeferredOrder.getId()){
            loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_FAILED);
            loanDeferredOrderMapper.updateById(loanDeferredOrder);
        }
        doRepaymentLastService.updateWalletOrderToFailed(walletNo, true);
    }

    private void doRepayAllWithWalletNotAll(JSONObject rsp, LoanIou loanIou, String cardId, BigDecimal amtWallet, String walletNo, BigDecimal minPay) {
        log.info("主动还款<非>延期+钱包还款，钱包大于0：参数:serialNo:{},cardId:{}", loanIou.getLoanSerialNo(), cardId);
        CustBankCard bankCard = getCustBankCard(cardId);
        setCardCanNotUse(loanIou.getLoanSerialNo(), bankCard, 3);
        // 钱包支付非全额还款，不需要等待卡支付回调进行冲账，06-15有沟通
        try {
            // 创建订单 createRepaymentOrder 钱包的 状态为5
            RepaymentOrder repaymentOrderWallet = repaymentService.createRepaymentOrderForfWalletNotAll(BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERAT_WALLET, amtWallet, walletNo, loanIou);
            if (null != repaymentOrderWallet) {
                CreditAccount creditAccount = creditAccountService.getNormalAcountOnLoan(repaymentOrderWallet.getCustNo());
                SendResult sendResult = repaymentMqService.selfWalletForBfenRepaymentMq(repaymentOrderWallet, creditAccount.getId());
                if (!(SendStatus.SEND_OK).equals(sendResult.getSendStatus())) {
                    log.info("钱包部分支付还款，发送mq失败：{}", sendResult);
                    doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                    rsp.put("result", "0");
                    return;
                }
            } else {
                doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                rsp.put("result", "0");
                return;
            }
        } catch (Exception e) {
            log.error("钱包部分支付还款",e);
            doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
            throw new BusinessException(RspEnmu.NETWORK_BUSY);
        }
        // 创建paystask的
        // 卡支付的钱
        BigDecimal paystaskAmt = minPay.subtract(amtWallet);
        // 大于50才走下面
        //  iBRepaymentService.checkAmount(loanIou, reduceSource);
        boolean result = repaymentService.createRepaymentOrderAndPayTransForNoSuccess(paystaskAmt, loanIou, bankCard, walletNo);
        rsp.put("result", result ? "1" : "0");

    }

    /**
     * 钱包延期还款，部分还款
     *
     * @param loanDeferredOrder
     */
    private boolean createRepaymentOrderDeferWallet(LoanDeferredOrder loanDeferredOrder,
                                                    BigDecimal amtWallet, String walletNo, LoanIou loanIou) {
        return repaymentService.createRepaymentOrderForDeferBfWallet(loanDeferredOrder, amtWallet, walletNo, loanIou);

    }


    /**
     * 钱包全额支付延期还款
     *
     * @param rsp
     * @param loanIou
     * @param productDeferredInfo
     */
    private void doRepayDeferredForWclletPayOk(JSONObject rsp,
                                               LoanIou loanIou, ProductDeferredInfo productDeferredInfo,
                                               BigDecimal amtWallet, String walletNo) {
        LoanDeferredOrder loanDeferredOrder = new LoanDeferredOrder();
        try {
            // 创建订单 钱包类型的订单
            loanDeferredOrder = createLoanDeferredOrder(loanIou.getLoanSerialNo(), productDeferredInfo.getId(), null, walletNo, BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER_WALLET);
            RepaymentOrder repaymentOrder = createLoanDeferredOrderAndReparOrder(loanIou, productDeferredInfo, amtWallet, walletNo,loanDeferredOrder);
            if (null != repaymentOrder) {
                SendResult sendResult = repaymentMqService.selfdeferWalletForAllPayRepaymentMq(loanIou, productDeferredInfo, repaymentOrder, amtWallet, walletNo);
                if (!SendStatus.SEND_OK.equals(sendResult.getSendStatus())) {
                    updateLoanDeferredOrderFailed(walletNo, loanDeferredOrder);
                    rsp.put("result", "0");
                    return;
                }
                rsp.put("result", "1");
            } else {
                log.info("钱包全额支付延期还款，创建订单失败");
                rsp.put("result", "0");
                updateLoanDeferredOrderFailed(walletNo, loanDeferredOrder);
            }
        } catch (Exception e) {
            log.error("钱包全额支付延期还款err",e);
            updateLoanDeferredOrderFailed(walletNo, loanDeferredOrder);
            throw new BusinessException(RspEnmu.NETWORK_BUSY);
        }

    }

    /**
     * 购买延期包
     * 创建 loan_deferred_order 状态状态9申请中，insert成功后
     * ，创建RepaymentOrder发起payStask请求
     * ，成功后冲账，账目流水，其他异常，进入10分钟定时任务（3小时轮询）
     *
     * @param rsp
     * @param serialNo
     * @param cardId
     */
    private void doRepayDeferred(JSONObject rsp, String serialNo, String cardId, int deferredId) {
        log.info("主动还款延期还款：参数:serialNo:{},cardId:{}", serialNo, cardId);
        CustBankCard bankCard = getCustBankCard(cardId);
        setCardCanNotUse(serialNo, bankCard, 3);
        //创建 loan_deferred_order 状态状态9申请中
        LoanDeferredOrder loanDeferredOrder = createLoanDeferredOrder(serialNo, deferredId, cardId, null, BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER);
        if (null != loanDeferredOrder) {
            // 创建订单createRepaymentOrder
            boolean result = repaymentService.createRepaymentOrderAndPayTransForDefer(serialNo, bankCard, loanDeferredOrder);
            if(!result){
                // 先进行取消延期订单判断是否有钱包
                loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_FAILED);
                loanDeferredOrderMapper.updateById(loanDeferredOrder);
            }
            rsp.put("result", result ? "1" : "0");
        } else {
            rsp.put("result", "0");
        }
    }

    private RepaymentOrder createLoanDeferredOrderAndReparOrder(LoanIou loanIou, ProductDeferredInfo productDeferredInfo, BigDecimal amtWallet, String walletNo,LoanDeferredOrder loanDeferredOrder) {
        RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderForDeferWalletSuccess(
                loanIou,
                BizConstants.LOAN_REPAYMENT_ORDER_TYPE_OPERATEDEFER_WALLET,
                "Active",
                loanDeferredOrder, amtWallet, walletNo);
        return repaymentOrder;
    }

    private LoanDeferredOrder createLoanDeferredOrder(String serialNo, long deferredId, String cardId, String walletNo, String actionType) {
        LoanIou loanIou = loanIouMapper.getLoanIouByLoanSerialNo(serialNo);
        ProductInfo productInfo = processForIouDefferredService.getProductId(loanIou);
        ProductDeferredInfo productDeferredInfo = productDeferredInfoMapper.selectById(deferredId);

        BigDecimal leftAmt = loanIou.getLoanAmt().subtract(loanIou.getRepaidPrincipal());

        LoanDeferredOrder loanDeferredOrder = new LoanDeferredOrder();

        loanDeferredOrder.setLoanDeferOrderNo(IdWorker.getId());
        loanDeferredOrder.setCustNo(loanIou.getCustNo());
        loanDeferredOrder.setActionType(actionType);
        loanDeferredOrder.setLoanSerialNo(serialNo);
        loanDeferredOrder.setProductId(productInfo.getId());
        loanDeferredOrder.setProductCode(productInfo.getProductCode());
        loanDeferredOrder.setProductDeferredId(deferredId);
        loanDeferredOrder.setCreditRating(productInfo.getCreditRating());
        loanDeferredOrder.setWalletNo(walletNo);//repayorder transF需要

        loanDeferredOrder.setInterestRate(productDeferredInfo.getInterestRate());
        loanDeferredOrder.setServiceRate(productDeferredInfo.getServiceRate());

        loanDeferredOrder.setNumDeferredDay(productDeferredInfo.getNumDeferredDay());
        loanDeferredOrder.setNumDeferredTimes(productDeferredInfo.getNumDeferredTimes());
        loanDeferredOrder.setNumDeferredRetainDay(productDeferredInfo.getNumDeferredRetainDay());
        loanDeferredOrder.setMinRepayPrincipal(productDeferredInfo.getMinRepayPrincipal());
        loanDeferredOrder.setMaxRepayPrincipal(productDeferredInfo.getMaxRepayPrincipal());
        loanDeferredOrder.setExpireTime(productDeferredInfo.getExpireTime());
        loanDeferredOrder.setShowIsActive(productDeferredInfo.getShowIsActive());
        loanDeferredOrder.setDeferredServiceFee(leftAmt.multiply(productDeferredInfo.getServiceRate()));
        loanDeferredOrder.setDeferredInterestFee(leftAmt.multiply(productDeferredInfo.getInterestRate()).multiply(new BigDecimal(productDeferredInfo.getNumDeferredDay())));

        loanDeferredOrder.setLoanPrincipal(loanIou.getLoanPrincipal());
        loanDeferredOrder.setRepaidPrincipal(loanIou.getRepaidPrincipal());
        loanDeferredOrder.setServiceFee(loanIou.getServiceFee());
        loanDeferredOrder.setRepaidServiceFee(loanIou.getRepaidServiceFee());
        loanDeferredOrder.setLoanInterest(loanIou.getLoanInterest());
        loanDeferredOrder.setRepaidInterest(loanIou.getRepaidInterest());
        loanDeferredOrder.setLateFee(loanIou.getRepaidLateFee());


        loanDeferredOrder.setCardId(cardId);
        loanDeferredOrder.setStatus(LoanDeferredOrder.STATUS_WAIT);
        loanDeferredOrder.setCreateBy("system");

        loanDeferredOrder.setRepayAmt(processForIouDefferredService.getMinPay(loanIou, productDeferredInfo));
        int numInsert = loanDeferredOrderMapper.insert(loanDeferredOrder);
        if (numInsert == 1) {
            return loanDeferredOrder;
        } else {
            return null;
        }
    }


    /**
     * 开始还款
     *
     * @param rsp
     * @param serialNo
     * @param cardId
     */
    private void doRepay(JSONObject rsp, String serialNo, String cardId) {
        log.info("主动还款参数：serialNo = {}，cardId = {}", serialNo, cardId);
        CustBankCard bankCard = getCustBankCard(cardId);
        setCardCanNotUse(serialNo, bankCard, 3);
        // boolean result = bLoanInfoService.doRepaymentAction(serialNo, bankCard,getReduceFlag(serialNo));
        //判断是否存在减免获取减免标示
        String reduceFlag = getReduceFlag(serialNo);
        // 创建订单-执行代扣
        boolean result = repaymentService.createRepaymentOrderAndPayTrans(serialNo, bankCard, reduceFlag);
        rsp.put("result", result ? "1" : "0");
    }

    private CustBankCard getCustBankCard(String cardId) {
        CustBankCard bankCardParam = new CustBankCard();
        bankCardParam.setCustNo(getCustNo());
        bankCardParam.setId(Long.parseLong(cardId));
        CustBankCard bankCard = custBankCardService.getDetailByCustIdCardId(bankCardParam);
        if (null == bankCard) {
            throw new BusinessException(RspEnmu.SYSTEM_SYSDATA_EXCEPTION);
        }
        return bankCard;
    }

    /**
     * 设置当前卡?小时不能使用
     *
     * @param serialNo
     * @param bankCard
     * @param hours    ?
     */
    private void setCardCanNotUse(String serialNo, CustBankCard bankCard, int hours) {
//        String redisKey = BizConstants.LOAN_REPAY_CARD + serialNo;
//        checkRedisHasKey(redisKey);
//        redisCache.setCacheObject(redisKey, bankCard.getCardNumber(), hours, TimeUnit.HOURS);
    }

    /**
     * 判断是否存在减免
     *
     * @param serialNo
     * @return 返回减免flag
     */
    private String getReduceFlag(String serialNo) {
        String reduceFlag = "noReduce";
        BigDecimal reduceAmt = doCalCustReduce.checkCustReduce(serialNo).getReduceAmont();
        if (reduceAmt.compareTo(BigDecimal.ZERO) > 0) {
            reduceFlag = "hasReduce";
        }
        return reduceFlag;
    }

    /**
     * 同一张银行卡3小时内只能发起一次主动代扣申请
     */
    private void checkRedisHasKey(String redisKey) {
        Object cacheObject = redisCache.getCacheObject(redisKey);
        if (Func.isNotEmpty(cacheObject)) {
            throw new BusinessException(RspEnmu.REPAYMENT_ORDER_IN_TRANSIT);
        }
    }

    /**
     * 验证交易密码
     */
    public boolean isPasswordCheck(String userUUId, String password) {
        //验证交易密码
        List<CustTransactionSetting> settingList =
                custTransactionSettingService.selectCustTransactionSettingList(getQueryCustTransactionSetting(userUUId));
        if (settingList.size() <= 0) {
            throw new BusinessException(RspEnmu.NOT_SET_TRADE_PASSWORD);
        }
        return checkPwdPass(password, settingList);
    }

    private CustTransactionSetting getQueryCustTransactionSetting(String userUUId) {
        CustTransactionSetting query = new CustTransactionSetting();
        query.setUserId(userUUId);
        query.setState(UserConstants.NORMAL);
        return query;
    }

    private boolean checkPwdPass(String password, List<CustTransactionSetting> settingList) {
        CustTransactionSetting CustTransactionSetting = settingList.get(0);
        if (StringUtils.isBlank(CustTransactionSetting.getPassword())) {
            throw new BusinessException(RspEnmu.NOT_SET_TRADE_PASSWORD);
        }
        //判断密码是否正确
        if (!bCryptPasswordEncoder.matches(password, CustTransactionSetting.getPassword())) {
            throw new BusinessException(RspEnmu.T_PASSWORD_ERR);
        }
        return true;
    }

    public boolean checkCanBuyDefer(int deferredId, String serialNo) {
        log.info("检查是否能够购买，{},{}", deferredId, serialNo);
        LoanIou loanIou = loanIouService.getLoanIouByLoanSerialNo(serialNo);
        ProductInfo productInfo = productInfoMapper.selectById(loanIou.getProductId());
        BigDecimal principal = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());
        try {
            Date repayDate = DateUtils.parseDate(loanIou.getRepayDate(), DateUtils.YYYY_MM_DD_SLASH);
            int periodNum = loanIou.getPeriodNum();
            if (1 == loanIou.getIsDeferred()) {
                // 存在子借据使用了延期包
                repayDate = DateUtils.parseDate(loanIou.getDeferredRepayDate(), DateUtils.YYYY_MM_DD_SLASH);
                //此处是加上了延期的天数
                periodNum = loanIou.getDeferredPeriodNum();
            }
            ProductDeferredInfo productDeferredInfo = productDeferredInfoMapper.selectByIdForCheck(deferredId,
                    principal,
                    DateUtils.parseDateToStr("yyyy-MM-dd 23:59:59", repayDate),
                    periodNum,
                    productInfo.getDeferredMaxDays());
            if (null != productDeferredInfo) {
                return true;
            }
        } catch (ParseException e) {
            log.error("日期转换错误：", e);
            return false;
        }
        return false;
    }

    /**
     * 催收调用客服再掉业务系统：处理催收钱包代扣
     *
     * @param loanSerialNo
     * @return
     */
    public JSONObject collectionWalletRepay(String loanSerialNo) {
        log.info("处理催收钱包代扣，检查代扣:loanSerialNo:{}", loanSerialNo);
        JSONObject res = new JSONObject();
        res.put("status", false);
        // 服务器检查借据状态是否已结清
        LoanIou loanIou = loanIouMapper.getLoanIouByLoanSerialNo(loanSerialNo);
        if (LoanIou.LOAN_IOU_STATUS_SETTLE == loanIou.getIouStatus()) {
            res.put("msg", "The IOU has been settled, please refresh the page");
            return res;
        }
        // 检查是否有生效的延期订单，且到期日-当天日期>3天：
        if (null != loanIou.getIsDeferred() && 1 == loanIou.getIsDeferred()
                && DateUtils.daysBetween(new Date(), DateUtils.parseDate(loanIou.getDeferredRepayDate())) > 3) {
            res.put("msg", "The customer has handled 'Loan Extension'");
            return res;
        }
        // 检查是否有处理中的延期订单：
        LoanDeferredOrder loanDeferredOrder = loanDeferredOrderMapper.selectOneByCustNoStatusApply(loanIou.getCustNo());
        if (null != loanDeferredOrder) {
            res.put("msg", "The customer has applied for 'Loan Extension'  and is still in process");
            return res;
        }
        // 钱包可用余额<=50，则返回催收系统提示用户钱包余额不足
        // 先查询钱包可用余额，
        BigDecimal leftWalletAmt = doRepaymentLastService.getWalletAmount(loanIou.getCustNo());
        BigDecimal collectionWalletRepayMmin = new BigDecimal(sysConfigService.selectConfigByKey("collection-wallet-repay-min"));
        if (leftWalletAmt.compareTo(collectionWalletRepayMmin) < 0) {
            log.info("查询钱包余额小于50,{},{}", leftWalletAmt, collectionWalletRepayMmin);
            res.put("msg", "The available balance of the customer's wallet is less than N" + collectionWalletRepayMmin + ". Uable to repay");
            return res;
        }
        return dealCollectionWalletRepay(loanIou, collectionWalletRepayMmin);
    }
//
//    @PostConstruct
//    public void test() {
//        LoanIou loanIou = loanIouMapper.getLoanIouByLoanSerialNo("2021080974313365504");
//        System.out.println(dealCollectionWalletRepay(loanIou,new BigDecimal("50")).toJSONString());
//    }

    /**
     * 验证通过后，开始进行冲账
     *
     * @param loanIou
     * @return
     */
    private JSONObject dealCollectionWalletRepay(LoanIou loanIou, BigDecimal collectionWalletRepayMmin) {
        log.info("处理催收钱包代扣loanSerialNo:{},进行代扣", loanIou.getLoanSerialNo());
        JSONObject res = new JSONObject();
        res.put("status", false);
        BigDecimal minPay = LoanIou.calculationOverdueAmount(loanIou);
        log.info("处理催收钱包代扣loanSerialNo:{},minPay:{},进行代扣", loanIou.getLoanSerialNo(), minPay);
        // 生成等待还款的订单状态5还款中，，调用钱包冻结需要的金额
        // repaymentOrder 的还款金额先为 minPay ，没有请求钱包，先生成为5还款中，后面请求成功后去更新
        RepaymentOrder repaymentOrder = bLoanInfoService.createRepaymentOrderRepayAllWalletNoSuccess(
                loanIou,
                BizConstants.LOAN_REPAYMENT_ORDER_TYPE_COLLECTION_WALLET,
                "", minPay, "-1");
        if (null != repaymentOrder) {
            // 请求钱包
            try {
                JSONObject amtWalletObj = doRepaymentLastService.getAmtWallet(minPay, loanIou.getCustNo(), loanIou.getLoanSerialNo(), false);
//                amtWalletObj.put("amtWallet",2841);
//                amtWalletObj.put("walletNo",2);
                BigDecimal amtWallet = amtWalletObj.getBigDecimal("amtWallet");
                String walletNo = amtWalletObj.getString("walletOrderNo");
                if (amtWallet.compareTo(BigDecimal.ZERO) == 0) {
                    log.info("处理催收钱包代扣loanSerialNo:{}，钱包可用余额小于50返回失败", loanIou.getLoanSerialNo());
                    res.put("msg", "The available balance of the customer's wallet is less than N" + collectionWalletRepayMmin + ". Uable to repay");
                    udpateRepaymentOrderFaild(repaymentOrder, "钱包可用余额小于50");
                    // 进行解冻
                    // doRepaymentLastService.updateWalletOrderToFailed(walletNo,false);
                    return res;
                } else {
                    repaymentOrder.setRepaymentAmt(amtWallet);
                    repaymentOrder.setPayTransSerialNo(walletNo);
                    repaymentOrderMapper.updateById(repaymentOrder);

                    SendResult sendResult = repaymentMqService.selfWalletForAllPayRepaymentMq(loanIou, repaymentOrder);
                    if (!(SendStatus.SEND_OK).equals(sendResult.getSendStatus())) {
                        log.info("处理催收钱包代扣loanSerialNo:{}，发送mq失败，{}", loanIou.getLoanSerialNo());
                        udpateRepaymentOrderFaild(repaymentOrder, "mq发送失败");
                        doRepaymentLastService.updateWalletOrderToFailed(walletNo, false);
                        res.put("msg", "system err!!");
                        return res;
                    }
                    res.put("status", true);
                    res.put("repaymentOrderId", repaymentOrder.getId());
                    res.put("amt", repaymentOrder.getRepaymentAmt());
                    res.put("msg", "Wallet Deduction application has been submitted successfully!");
                    log.info("处理催收钱包代扣loanSerialNo:{}，发送mq成功", loanIou.getLoanSerialNo());
                }
            } catch (Exception e) {
                log.error("处理催收钱包代扣loanSerialNo:{}，catch错误", loanIou.getLoanSerialNo());
                udpateRepaymentOrderFaild(repaymentOrder, "冻结钱包、mq发送，网络错误，等");
                throw new RuntimeException(e);
            }
        } else {
            log.info("处理催收钱包代扣,生成order失败:loanSerialNo:{}", loanIou.getLoanSerialNo());
            res.put("status", false);
            res.put("msg", "system err!!");
        }

        return res;
    }

    private void udpateRepaymentOrderFaild(RepaymentOrder repaymentOrder, String remark) {
        repaymentOrder.setRepayStatus(BizConstants.REPAYMENT_ORDER_STATUS_FAIL);
        repaymentOrder.setRemark(remark);
        repaymentOrderMapper.updateById(repaymentOrder);
    }

    /**
     * 催收调用客服再掉业务系统：处理催钱包购买延期
     *
     * @param loanSerialNo,deferredId
     * @return
     */
    public JSONObject collectionWalletBuyDefer(String loanSerialNo, String deferredId) {
        log.info("处理催钱包购买延期:loanSerialNo:{},deferredId:{}", loanSerialNo, deferredId);
        JSONObject res = new JSONObject();
        res.put("status", false);
        // 检查是否存在延期中的订单
        LoanDeferredOrder loanDeferredOrder = loanDeferredOrderService.getOne(new QueryWrapper<LoanDeferredOrder>()
                .eq("loan_serial_no", loanSerialNo)
                .eq("status", LoanDeferredOrder.STATUS_WAIT)
                .last("limit 1")
        );
        if (null != loanDeferredOrder) {
            res.put("msg", "Loan Extension order is being processed, please try again later");
            return res;
        }
        // 检查延期包有效性
        boolean canBuy = checkCanBuyDefer(Integer.parseInt(deferredId), loanSerialNo);
        if (!canBuy) {
            res.put("msg", RspEnmu.PRODUCT_DEFERRED_IS_DOWN.getMessage());
            return res;
        }
        loanDeferredOrder = createLoanDeferredOrder(loanSerialNo, Long.parseLong(deferredId), null, null, BizConstants.LOAN_REPAYMENT_ORDER_TYPE_COLLECTION_WALLET_BUY_DEFER);
        if (null == loanDeferredOrder) {
            res.put("msg", RspEnmu.SYSTEM_BUSY.getMessage());
            return res;
        }
        // 创建redis 标示 过期时间
        double expMinutes = DateUtils.getDateDiff(DateUtils.DATE_INTERVAL_MINUTE, DateUtils.parseDate(DateFormatUtils.format(new Date(), DateUtils.YYYY_MM_DD + " 23:59:59")), new Date());
        String redisKey = "walletDefer_" + loanDeferredOrder.getCustNo();
        redisCache.setCacheObject(redisKey, loanDeferredOrder.getCustNo(), (int) expMinutes, TimeUnit.MINUTES);
        asyncRepayMentService.asyncWalletBuyDefer(loanDeferredOrder, true);
        res.put("msg", "Loan Extension application submitted successfully");
        res.put("status", true);
        return res;
    }

}
